home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hot Super Models
/
Hot Super Models.iso
/
unix
/
x11
/
xv200.tar
/
xv-2.00
/
xvevent.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-02
|
30KB
|
1,132 lines
/*
* xvevent.c - EventLoop and support routines for XV
*
* Author: John Bradley, University of Pennsylvania
* (bradley@cis.upenn.edu)
*
* Contains:
* int EventLoop()
* void DrawWindow(x,y,w,h)
* void WResize(w,h)
* void WRotate()
* void WCrop(w,h)
* void WUnCrop()
* void GetWindowPos(&xwa)
* void SetWindowPos(&xwa)
* static void TrackCrop(mx,my)
* static void CropKey(dx,dy,grow)
* static int Rect(x,y,x1,y1)
* void InvCropRect()
* static void TrackPicValues(mx,my)
* static int CheckForConfig()
* void SetEpicMode()
* int xvErrorHandler(disp, err)
*/
/*
* Copyright 1989, 1990, 1991, 1992 by John Bradley and
* The University of Pennsylvania
*
* Permission to use, copy, and distribute for non-commercial purposes,
* is hereby granted without fee, providing that the above copyright
* notice appear in all copies and that both the copyright notice and this
* permission notice appear in supporting documentation.
*
* The software may be modified for your own purposes, but modified versions
* may not be distributed.
*
* This software is provided "as is" without any expressed or implied warranty.
*
* The author may be contacted via:
* US Mail: John Bradley
* GRASP Lab, Room 301C
* 3401 Walnut St.
* Philadelphia, PA 19104
*
* Phone: (215) 898-8813
* EMail: bradley@cis.upenn.edu
*/
#define NEEDSTIME /* for -wait handling in eventloop */
#include "xv.h"
static int rotatesLeft = 0;
/* local function pre-definitions */
#ifdef __STDC__
static void WMaximize(void);
static void TrackCrop(int, int);
static void CropKey(int, int, int);
static int Rect(int, int, int, int);
static void TrackPicValues(int, int);
static int CheckForConfig(void);
#else
static void WMaximize(), TrackCrop(), CropKey(), TrackPicValues();
static int Rect(), CheckForConfig();
#endif
/****************/
int EventLoop()
/****************/
{
XEvent event;
int retval,done,waiting;
time_t orgtime, curtime;
/* note: there's no special event handling if we're using the root window.
if we're using the root window, we will recieve NO events for mainW */
done = retval = waiting = 0;
while (!done) {
if (waitsec > -1 && !waiting && XPending(theDisp)==0) {
/* we wanna wait, we haven't started waiting yet, and all pending
events (ie, drawing the image the first time) have been dealt with */
time(&orgtime);
waiting = 1;
}
if (waitsec == -1 || XPending(theDisp)>0) {
XNextEvent(theDisp, &event);
retval = HandleEvent(&event,&done);
}
else { /* no events. check wait status */
if (waitsec>-1 && waiting) {
time(&curtime);
if (curtime - orgtime < waitsec) sleep(1);
else {
if (waitloop) return NEXTLOOP;
else return NEXTQUIT;
}
}
}
} /* while (!done) */
return(retval);
}
/****************/
int HandleEvent(event, donep)
XEvent *event;
int *donep;
{
int done=0, retval=0;
switch (event->type) {
case ClientMessage: {
Atom proto, delwin;
XClientMessageEvent *client_event = (XClientMessageEvent *) event;
if (PUCheckEvent (event)) break; /* event has been processed */
proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
if (client_event->message_type == proto &&
client_event->data.l[0] == delwin) {
/* it's a WM_DELETE_WINDOW event */
if (client_event->window == infoW) InfoBox(0);
else if (client_event->window == gamW) GamBox(0);
else if (client_event->window == ctrlW) CtrlBox(0);
else if (client_event->window == dirW) DirBox(0);
else if (client_event->window == psW) PSDialog(0);
#ifdef HAVE_JPEG
else if (client_event->window == jpegW) JPEGDialog(0);
#endif
else if (client_event->window == mainW) exit(0);
}
}
break;
case Expose: {
XExposeEvent *exp_event = (XExposeEvent *) event;
int x,y,w,h;
Window win;
win = exp_event->window;
x = exp_event->x; y = exp_event->y;
w = exp_event->width; h = exp_event->height;
if (PUCheckEvent (event)) break; /* event has been processed */
if (PSCheckEvent (event)) break; /* event has been processed */
#ifdef HAVE_JPEG
if (JPEGCheckEvent(event)) break; /* event has been processed */
#endif
if (GamCheckEvent (event)) break; /* event has been processed */
/* if the window doesn't do intelligent redraw, drop all-1 exposes */
if (exp_event->count>0 && exp_event->window != mainW
&& exp_event->window != ctrlW
&& exp_event->window != dirW
&& exp_event->window != infoW) break;
if (win == mainW) {
if (DEBUG) fprintf(stderr,"EXPOSE: ");
if (!CheckForConfig()) {
if (DEBUG) fprintf(stderr,"No configs. Expose %d,%d %dx%d\n",x,y,w,h);
if (DEBUG) XClearArea(theDisp, mainW, x,y,w,h, False);
DrawWindow(x,y,w,h);
if (but[BCROP].active) {
XRectangle xr;
xr.x = x; xr.y = y; xr.width = w; xr.height = h;
XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted);
InvCropRect();
XSetClipMask(theDisp,theGC,None);
}
}
else
if (DEBUG)
fprintf(stderr,"Ignoring expose event. Config pending\n");
}
else if (win == infoW) RedrawInfo(x,y,w,h);
else if (win == ctrlW) RedrawCtrl(x,y,w,h);
else if (win == nList.win) LSRedraw(&nList);
else if (win == nList.scrl.win) SCRedraw(&nList.scrl);
else if (win == dirW) RedrawDirW(x,y,w,h);
else if (win == dList.win) LSRedraw(&dList);
else if (win == dList.scrl.win) SCRedraw(&dList.scrl);
else if (win == dnamW) RedrawDNamW();
}
break;
case ButtonPress: {
XButtonEvent *but_event = (XButtonEvent *) event;
int i,x,y;
Window win;
win = but_event->window;
x = but_event->x; y = but_event->y;
if (PUCheckEvent (event)) break;
if (PSCheckEvent (event)) break;
#ifdef HAVE_JPEG
if (JPEGCheckEvent(event)) break;
#endif
if (GamCheckEvent (event)) break;
switch (but_event->button) {
case Button1:
if (win == mainW) TrackPicValues(x,y);
else if (win == ctrlW) {
int w,h;
if (MBClick(&dispMB, x,y)) {
if (MBTrack(&dispMB)) HandleDispMode();
break;
}
i=ClickCtrl(x,y);
switch (i) {
case BNEXT: retval= NEXTPIC; done=1; break;
case BPREV: retval= PREVPIC; done=1; break;
case BLOAD: SetDirFName(""); DirBox(BLOAD); break;
case BSAVE: DirBox(BSAVE);
break;
case BQUIT: retval= QUIT; done=1; break;
case BCROP: DoCrop(); break;
case BUNCROP: UnCrop(); break;
case BNORM: WResize(cWIDE/normFact, cHIGH/normFact); break;
case BMAX: WMaximize(); break;
case BUP10: w = (eWIDE*11)/10; h = (eHIGH*11)/10;
if (w==eWIDE) w++;
if (h==eHIGH) h++;
WResize(w,h);
break;
case BDN10: WResize((eWIDE*9)/10, (eHIGH*9)/10); break;
case BUP2: WResize(eWIDE*2, eHIGH*2); break;
case BDN2: WResize(eWIDE/2, eHIGH/2); break;
case B4BY3: w = eWIDE; h = (w * 3) / 4;
if (h>maxHIGH) { h = eHIGH; w = (h*4)/3; }
WResize(w,h);
break;
case BASPECT: FixAspect(1,&w,&h); WResize(w,h); break;
case BMAXPECT: { int w1,h1;
w1 = eWIDE; h1 = eHIGH;
eWIDE = dispWIDE; eHIGH = dispHIGH;
FixAspect(0,&w,&h);
eWIDE = w1; eHIGH = h1; /* play it safe */
WResize(w,h);
} break;
case BROTL: Rotate(1); break;
case BROTR: Rotate(0); break;
case BACROP: AutoCrop(); break;
case BFLIPH: Flip(0); break;
case BFLIPV: Flip(1); break;
case BSMOOTH: Smooth(); break;
case BDITH: ColorDither(NULL, eWIDE, eHIGH); break;
case BRAW: if (theImage!=NULL) XDestroyImage(theImage);
theImage = NULL;
Resize(eWIDE,eHIGH);
break;
case BINFO: InfoBox(!infoUp); break;
case BGAMMA: GamBox(!gamUp); break;
case BDELETE: if (DeleteCmd()) { done = 1; retval = DELETE; }
break;
default: break;
}
if (i==BFLIPH || i==BFLIPV || i==BSMOOTH || i==BDITH || i==BRAW) {
if (useroot) MakeRootPic();
else DrawWindow(0,0,eWIDE,eHIGH);
if (but[BCROP].active) InvCropRect();
SetCursors(-1);
}
}
else if (win == nList.win) {
i=LSClick(&nList,but_event);
if (i>=0) { done = 1; retval = i; }
}
else if (win == nList.scrl.win) SCTrack(&nList.scrl, x, y);
else if (win == dirW) {
i=ClickDirW(x,y);
switch (i) {
case S_BOK: if (dirUp == BLOAD) {
retval = LOADPIC;
done=1;
}
else if (dirUp == BSAVE) {
DoSave();
}
break;
case S_BCANC: DirBox(0); break;
}
}
else if (win == dList.win) {
i=LSClick(&dList,but_event);
SelectDir(i);
}
else if (win == dList.scrl.win) SCTrack(&dList.scrl, x,y);
else if (win == infoW) InfoBox(0); /* close info */
break;
case Button2: if (win == mainW) TrackCrop(x,y);
break;
case Button3: /* if using root, MUST NOT get rid of ctrlbox. */
if (!useroot) CtrlBox(!ctrlUp);
break;
default: break;
}
}
break;
case KeyPress: {
XKeyEvent *key_event = (XKeyEvent *) event;
char buf[128]; KeySym ks; XComposeStatus status;
int stlen, dealt, shift;
stlen = XLookupString(key_event,buf,128,&ks,&status);
dealt = 0;
if (PUCheckEvent (event)) break;
if (PSCheckEvent (event)) break;
#ifdef HAVE_JPEG
if (JPEGCheckEvent(event)) break;
#endif
if (GamCheckEvent (event)) break;
/* check for crop rect keys */
if (key_event->window == mainW /* && !dirUp */) {
dealt = 1; shift = key_event->state & ShiftMask;
if (ks==XK_Left || ks==XK_KP_4) CropKey(-1, 0, shift);
else if (ks==XK_Right || ks==XK_KP_6) CropKey( 1, 0, shift);
else if (ks==XK_Up || ks==XK_KP_8) CropKey( 0,-1, shift);
else if (ks==XK_Down || ks==XK_KP_2) CropKey( 0, 1, shift);
else dealt = 0;
if (dealt) break;
}
/* check for List keys */
if (key_event->window == ctrlW || key_event->window == dirW /*||dirUp*/) {
LIST *theList;
if (key_event->window == dirW /*|| dirUp*/) theList = &dList;
else theList = &nList;
dealt = 1;
if (ks==XK_Prior) LSKey(theList,LS_PAGEUP);
else if (ks==XK_Next) LSKey(theList,LS_PAGEDOWN);
else if (ks==XK_Up) LSKey(theList,LS_LINEUP);
else if (ks==XK_Down) LSKey(theList,LS_LINEDOWN);
else if (ks==XK_Home) LSKey(theList,LS_HOME);
else if (ks==XK_End) LSKey(theList,LS_END);
else dealt = 0;
if (theList == &dList && dealt) { /* changed dir selection */
SelectDir(-1); /* nothing was double-clicked */
}
if (dealt) break;
}
/* check dir filename arrows */
if (key_event->window == dirW && ks==XK_Left) { DirKey('\002'); break; }
if (key_event->window == dirW && ks==XK_Right) { DirKey('\006'); break; }
if (!stlen) break;
/* if dirUp, send all keystrokes to it OR NOT */
if (key_event->window == dirW /* || dirUp */) {
if (DirKey(buf[0])) XBell(theDisp,0);
}
else {
/* commands valid in any window */
switch (buf[0]) {
case '\t':
case ' ': FakeButtonPress(&but[BNEXT]); break;
case '\r':
case '\n': done = 1; retval = nList.selected; break;
case '\010':
case '\177': FakeButtonPress(&but[BPREV]); break;
case '\004': FakeButtonPress(&but[BDELETE]); break; /* ^D */
case '\014': FakeButtonPress(&but[BLOAD]); break; /* ^L */
case '\023': FakeButtonPress(&but[BSAVE]); break; /* ^S */
case 'q': FakeButtonPress(&but[BQUIT]); break;
case '?': if (!useroot) CtrlBox(!ctrlUp); break;
case 's': FakeButtonPress(&but[BSMOOTH]); break;
case 'd': FakeButtonPress(&but[BDITH]); break;
case 'r': FakeButtonPress(&but[BRAW]); break;
case 'a': FakeButtonPress(&but[BASPECT]); break;
case 'A': FakeButtonPress(&but[BACROP]); break;
case 'T': FakeButtonPress(&but[BROTL]); break;
case 't': FakeButtonPress(&but[BROTR]); break;
case 'h': FakeButtonPress(&but[BFLIPH]); break;
case 'v': FakeButtonPress(&but[BFLIPV]); break;
case '4': FakeButtonPress(&but[B4BY3]); break;
case 'c': FakeButtonPress(&but[BCROP]); break;
case 'u': FakeButtonPress(&but[BUNCROP]); break;
case 'n': FakeButtonPress(&but[BNORM]); break;
case 'm': FakeButtonPress(&but[BMAX]); break;
case 'M': FakeButtonPress(&but[BMAXPECT]); break;
case ',': FakeButtonPress(&but[BDN10]); break;
case '.': FakeButtonPress(&but[BUP10]); break;
case '<': FakeButtonPress(&but[BDN2]); break;
case '>': FakeButtonPress(&but[BUP2]); break;
case 'i': FakeButtonPress(&but[BINFO]); break;
case 'e': FakeButtonPress(&but[BGAMMA]); break;
case 'R': FakeButtonPress(&gbut[G_BRESET]); break;
case 'p': FakeButtonPress(&gbut[G_BAPPLY]); break;
case 'C': FakeButtonPress(&gbut[G_BMAXCONT]); break;
default: break;
}
}
}
break;
case ConfigureNotify: {
XConfigureEvent *conf_event = (XConfigureEvent *) event;
if (conf_event->window == mainW && !rotatesLeft) {
if (DEBUG) fprintf(stderr,"CONFIG: (%s) ",
conf_event->send_event ? "program" : "user");
if (CheckForConfig()) {
if (DEBUG) fprintf(stderr,"config pending. ignored\n");
}
else {
XEvent xev;
if (DEBUG) fprintf(stderr,"No configs pend.");
if (conf_event->width == eWIDE && conf_event->height == eHIGH) {
if (DEBUG) fprintf(stderr,"No redraw\n");
}
else {
if (DEBUG) fprintf(stderr,"Do full redraw\n");
Resize(conf_event->width, conf_event->height);
/* eat any pending expose events and do a full redraw */
while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
XExposeEvent *exp = (XExposeEvent *) &xev;
if (DEBUG)
fprintf(stderr," ate expose (%s) (count=%d) %d,%d %dx%d\n",
exp->send_event ? "program" : "user", exp->count,
exp->x, exp->y, exp->width, exp->height);
}
DrawWindow(0,0,conf_event->width, conf_event->height);
SetCursors(-1);
}
}
}
if (rotatesLeft>0) rotatesLeft--;
if (!rotatesLeft) SetCursors(-1);
}
break;
case CirculateNotify:
case MapNotify:
case DestroyNotify:
case GravityNotify:
case UnmapNotify: break;
case ReparentNotify: {
XReparentEvent *reparent_event = (XReparentEvent *) event;
if (DEBUG) {
fprintf(stderr,"Reparent: mainW=%x ->win=%x ->ev=%x ->parent=%x ",
mainW, reparent_event->window, reparent_event->event,
reparent_event->parent);
fprintf(stderr,"%d,%d\n", reparent_event->x, reparent_event->y);
}
if (reparent_event->window == mainW) {
ch_offx = reparent_event->x; /* offset required for ChangeAttr call */
ch_offy = reparent_event->y;
p_offx = p_offy = 0; /* topleft correction for WMs titlebar */
if (ch_offx == 0 && ch_offy == 0) {
/* looks like the user is running MWM or OLWM */
XWindowAttributes xwa;
/* first query the attributes of mainW. x,y should be the offset
from the parent's topleft corner to the windows topleft.
OLWM puts the info here */
XSync(theDisp, False);
XGetWindowAttributes(theDisp, mainW, &xwa);
if (DEBUG)
fprintf(stderr,"XGetAttr: mainW %d,%d %dx%d\n", xwa.x, xwa.y,
xwa.width, xwa.height);
if (xwa.x == 0 && xwa.y == 0) {
/* MWM, at least mine, puts 0's in those fields. To get the
info, we'll have to query the parent window */
XSync(theDisp, False);
XGetWindowAttributes(theDisp, reparent_event->parent, &xwa);
if (DEBUG)
fprintf(stderr,"XGetAttr: parent %d,%d %dx%d\n", xwa.x, xwa.y,
xwa.width, xwa.height);
}
else {
/* KLUDGE: if we're running olwm, xwa.{x,y} won't be 0,0.
in olwm, the window drifts down and right each time
SetWindowPos() is called. God knows why. Anyway, I'm
inserting a kludge here to increase 'ch_offx' and 'ch_offy'
by bwidth so that this drifting won't happen. No doubt this'll
screw up behavior on some *other* window manager, but it should
work with TWM, OLWM, and MWM (the big three) */
ch_offx += bwidth;
ch_offy += bwidth;
}
p_offx = xwa.x;
p_offy = xwa.y;
}
}
}
break;
case EnterNotify:
case LeaveNotify: {
XCrossingEvent *cross_event = (XCrossingEvent *) event;
if (cross_event->window != mainW) break;
if (cross_event->type == EnterNotify && LocalCmap && !ninstall)
XInstallColormap(theDisp,LocalCmap);
if (cross_event->type == LeaveNotify && LocalCmap && !ninstall)
XUninstallColormap(theDisp,LocalCmap);
}
break;
default: break; /* ignore unexpected events */
} /* switch */
*donep = done;
return(retval);
}
/***********************************/
void DrawWindow(x,y,w,h)
int x,y,w,h;
{
if (theImage)
XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h);
else
if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n");
}
/***********************************/
void WResize(w,h)
int w,h;
{
XWindowAttributes xwa;
RANGE(w,1,maxWIDE); RANGE(h,1,maxHIGH);
if (useroot) {
Resize(w,h);
MakeRootPic();
SetCursors(-1);
return;
}
/* determine if new size goes off edge of screen. if so move window so it
doesn't go off screen */
GetWindowPos(&xwa);
if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
cmd,w,h,xwa.x,xwa.y);
/* resize the window */
xwa.width = w; xwa.height = h;
SetWindowPos(&xwa);
}
/***********************************/
static void WMaximize()
{
XWindowAttributes xwa;
if (useroot) WResize(dispWIDE, dispHIGH);
else {
xwa.x = xwa.y = 0;
xwa.width = dispWIDE;
xwa.height = dispHIGH;
SetWindowPos(&xwa);
}
}
/***********************************/
void WRotate()
{
/* rotate the window and redraw the contents */
if (but[BCROP].active) BTSetActive(&but[BCROP],0);
if (useroot) {
MakeRootPic();
SetCursors(-1);
return;
}
if (eWIDE == eHIGH) { /* no configure events will be gen'd */
Resize(eWIDE, eHIGH); /* to regen Ximage */
DrawWindow(0, 0, eWIDE, eHIGH);
SetCursors(-1);
}
else {
rotatesLeft++;
WResize(eWIDE, eHIGH);
}
}
/***********************************/
void WCrop(w,h)
int w,h;
{
XWindowAttributes xwa;
if (useroot) {
Resize(w,h); /* generate new epic and theImage */
MakeRootPic();
SetCursors(-1);
return;
}
/* we want to move window to old x,y + crx1,cry1 */
GetWindowPos(&xwa);
xwa.x += crx1; xwa.y += cry1;
xwa.width = w; xwa.height = h;
SetWindowPos(&xwa);
}
/***********************************/
void WUnCrop()
{
int w,h;
XWindowAttributes xwa;
/* to uncrop, I need to know the old values of cXOFF and cYOFF (cx,cy), and
the old values of cWIDE,cHIGH, eWIDE, eHIGH. NOTE that the idea here
is to, if possible, uncrop by wrapping the rest of the picture around
the currently visible hunk. */
if (!useroot) GetWindowPos(&xwa);
/* calculate w,h: based on concept of trying to show uncropped picture
with same expansion ratios. If this isn't possible (w or h bigger
than screen), just go to good ol' 1:1 expansion */
w = (pWIDE * eWIDE) / cWIDE; h = (pHIGH * eHIGH) / cHIGH;
if (w>maxWIDE || h>maxHIGH) {
w=pWIDE / normFact; h=pHIGH / normFact;
if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
xwa.width = w; xwa.height = h;
if (!useroot) SetWindowPos(&xwa);
}
else {
xwa.x = xwa.x - (cXOFF*eWIDE)/cWIDE; xwa.y = xwa.y - (cYOFF*eHIGH)/cHIGH;
if (xwa.x<0) xwa.x = 0;
if (xwa.y<0) xwa.y = 0;
xwa.width = w; xwa.height = h;
if (!useroot) SetWindowPos(&xwa);
}
if (useroot) {
cpic = pic; cWIDE = pWIDE; cHIGH = pHIGH;
Resize(xwa.width, xwa.height); /* generate new epic and theImage */
MakeRootPic();
SetCursors(-1);
return;
}
}
/***********************************/
void GetWindowPos(xwa)
XWindowAttributes *xwa;
{
Window child;
/* returns the x,y,w,h coords of mainW. x,y are relative to rootW
the border is not included (x,y map to top-left pixel in window) */
/* Get the window width/height */
XGetWindowAttributes(theDisp,mainW,xwa);
/* Get the window origin */
XTranslateCoordinates(theDisp,mainW,rootW,0,0,&xwa->x,&xwa->y,&child);
}
/***********************************/
void SetWindowPos(xwa)
XWindowAttributes *xwa;
{
/* sets window x,y,w,h values */
Window root, parent, *children, child;
unsigned int nchildren;
int x, y, w, h, xact, yact;
XWindowChanges xwc;
/* Adjust from window origin, to border origin */
xwc.x = xwa->x - xwa->border_width - ch_offx;
xwc.y = xwa->y - xwa->border_width - ch_offy;
if (!xwa->border_width) xwa->border_width = bwidth;
xwc.border_width = xwa->border_width;
/* if we're less than max size in one axis, allow window manager doohickeys
on the screen */
if (xwa->width < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
xwc.width = xwa->width;
xwc.height = xwa->height;
if (DEBUG) {
fprintf(stderr,"SWP: xwa=%d,%d %dx%d xwc=%d,%d %dx%d off=%d,%d bw=%d\n",
xwa->x, xwa->y, xwa->width, xwa->height,
xwc.x, xwc.y, xwc.width, xwc.height, p_offx, p_offy,
xwa->border_width);
}
#ifndef DXWM
/* Move/Resize the window. */
XConfigureWindow(theDisp, mainW,
CWX | CWY | CWWidth | CWHeight /*| CWBorderWidth*/, &xwc);
#endif
}
/***********************************/
static void TrackCrop(mx,my)
int mx,my;
{
Window rW,cW;
int rx,ry,ox,oy,x,y,active;
unsigned int mask;
if (but[BCROP].active) { /* turn off old cropping rectangle */
XSetFunction(theDisp,theGC,GXinvert);
Rect(crx1,cry1,crx2,cry2);
XSetFunction(theDisp,theGC,GXcopy);
}
active = 0;
SetCropString(active);
crx1 = ox = mx; cry1 = oy = my; /* nail down one corner */
while (1) {
if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
if (!(mask & Button2Mask)) break; /* button released */
if (x!=ox || y!=oy) { /* moved. erase and redraw */
crx2 = x; cry2 = y;
XSetFunction(theDisp,theGC,GXinvert);
Rect(crx1,cry1,ox,oy);
active = Rect(crx1,cry1,crx2,cry2);
XSetFunction(theDisp,theGC,GXcopy);
XFlush(theDisp);
ox=crx2; oy=cry2;
if (infoUp) SetCropString(active);
}
}
}
RANGE(crx1,0,eWIDE); RANGE(cry1,0,eHIGH);
RANGE(crx2,0,eWIDE); RANGE(cry2,0,eHIGH);
BTSetActive(&but[BCROP],active);
SetCropString(active);
}
/***********************************/
static void CropKey(dx,dy,grow)
int dx,dy,grow;
{
int x1,x2,y1,y2,active;
if (!but[BCROP].active) return;
/* x1,y1 = top-left, x2,y2 = bot-right */
if (crx1<crx2) { x1=crx1; x2=crx2; } else { x1=crx2; x2=crx1; }
if (cry1<cry2) { y1=cry1; y2=cry2; } else { y1=cry2; y2=cry1; }
if (!grow) { /* move the rectangle */
x1 += dx; x2 += dx; y1 += dy; y2 += dy;
if (x1<0 || x2>eWIDE) { x1 -= dx; x2 -= dx; }
if (y1<0 || y2>eHIGH) { y1 -= dy; y2 -= dy; }
}
else { /* grow the rectangle, pref. keeping top-left anchored */
x2 += dx; y2 += dy;
if (x2>eWIDE) {
x1 -= dx; x2 -= dx;
if (x1<0) x1=0;
}
if (y2>eHIGH) {
y1 -= dy; y2 -= dy;
if (y1<0) y1=0;
}
}
XSetFunction(theDisp,theGC,GXinvert);
Rect(crx1,cry1,crx2,cry2);
crx1 = x1; cry1 = y1; crx2 = x2; cry2 = y2;
active = Rect(crx1,cry1,crx2,cry2);
XSetFunction(theDisp,theGC,GXcopy);
BTSetActive(&but[BCROP], active);
SetCropString(active);
}
/***********************************/
static int Rect(x,y,x1,y1)
int x,y,x1,y1;
{
int w,h;
/* returns 0 if it didn't draw anything (rect is too small), 1 if it did */
w = abs(x-x1); h = abs(y-y1);
if (x>x1) x = x1;
if (y>y1) y = y1;
/* keep rectangle inside window */
if (x<0) { w+=x; x=0; }
if (y<0) { h+=y; y=0; }
if (x+w>eWIDE) w=eWIDE-x;
if (y+h>eHIGH) h=eHIGH-y;
if (w<4 || h<4) return 0; /* too small */
XSetPlaneMask(theDisp, theGC, AllPlanes);
XDrawRectangle(theDisp, mainW, theGC, x, y, w-1, h-1);
XSetPlaneMask(theDisp, theGC, 1L);
XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-3, h-3);
XSetPlaneMask(theDisp, theGC, AllPlanes);
return 1;
}
/***********************************/
void InvCropRect()
{
XSetFunction(theDisp,theGC,GXinvert);
Rect(crx1,cry1,crx2,cry2);
XSetFunction(theDisp,theGC,GXcopy);
}
/***********************************/
static void TrackPicValues(mx,my)
int mx,my;
{
Window rW,cW;
int rx,ry,ox,oy,x,y;
unsigned int mask;
int ty, w, ecol;
char foo[64];
unsigned long wh, bl;
char *str = "8888,8888 = 123,123,123 (123,123,123 HSV)";
wh = infobg; bl = infofg;
/* do a colormap search for black and white if LocalCmap
and use those colors instead of infobg and infofg */
if (LocalCmap) {
XColor ctab[256];
int i;
long cval;
for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
XQueryColors(theDisp,LocalCmap,ctab,nfcols);
/* find 'blackest' pixel */
cval = 0x10000 * 3;
for (i=0; i<nfcols; i++)
if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) {
cval = ctab[i].red + ctab[i].green + ctab[i].blue;
bl = ctab[i].pixel;
}
/* find 'whitest' pixel */
cval = -1;
for (i=0; i<nfcols; i++)
if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
cval = ctab[i].red + ctab[i].green + ctab[i].blue;
wh = ctab[i].pixel;
}
}
XSetFont(theDisp, theGC, monofont);
w = XTextWidth(monofinfo, str, strlen(str));
if (my > eHIGH/2) ty = 0;
else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
ox = oy = -1; /* kludge to force redraw first time through */
XSetForeground(theDisp, theGC, bl);
XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8,
(monofinfo->ascent+monofinfo->descent) + 4);
XSetForeground(theDisp, theGC, wh);
XSetBackground(theDisp, theGC, bl);
foo[0] = '\0';
RANGE(x,0,eWIDE-1); RANGE(y,0,eHIGH-1);
rx = cXOFF + (x * cWIDE) / eWIDE;
ry = cYOFF + (y * cHIGH) / eHIGH;
ecol = pic[ry * pWIDE + rx];
while (1) {
int px, py, pix;
if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
if (!(mask & Button1Mask)) break; /* button released */
RANGE(x,0,eWIDE-1);
RANGE(y,0,eHIGH-1);
px = cXOFF + (x * cWIDE) / eWIDE;
py = cYOFF + (y * cHIGH) / eHIGH;
if (px!=ox || py!=oy) { /* moved. erase and redraw */
double h1, s1, v1;
ecol = pix = pic[py * pWIDE + px];
rgb2hsv(rcmap[pix],gcmap[pix],bcmap[pix],&h1,&s1,&v1);
if (h1<0.0) h1 = 0.0; /* map 'NOHUE' to 0.0 */
sprintf(foo,"%4d,%4d = %3d,%3d,%3d (%3d %3d %3d HSV)",
px, py, rcmap[pix],gcmap[pix],bcmap[pix],
(int) h1, (int) (s1 * 100), (int) (v1 * 100));
XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent,
foo, strlen(foo));
ox = px; oy = py;
}
}
}
if (foo[0]) XStoreBytes(theDisp, foo, strlen(foo));
XSetFont(theDisp, theGC, mfont);
DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
if (ecol != editColor) ChangeEC(ecol);
}
/***********************************/
static Bool IsConfig(dpy, ev, arg)
Display *dpy;
XEvent *ev;
char *arg;
{
XConfigureEvent *cev;
if (ev->type == ConfigureNotify) {
cev = (XConfigureEvent *) ev;
if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
*arg = 1;
}
return False;
}
/***********************************/
static int CheckForConfig()
{
XEvent ev;
char foo;
/* returns true if there's a config event in which mainW changes size
in the event queue */
XSync(theDisp, False);
foo = 0;
XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
return foo;
}
/************************************************************************/
void SetEpicMode()
{
if (epicmode == EM_RAW) {
BTSetActive(&but[BRAW], 0);
BTSetActive(&but[BDITH], (ncols>0) ); /* only enable dith if ncols>0 */
BTSetActive(&but[BSMOOTH],1);
}
else if (epicmode == EM_DITH) {
BTSetActive(&but[BRAW], 1);
BTSetActive(&but[BDITH], 0);
BTSetActive(&but[BSMOOTH],1);
}
else if (epicmode == EM_SMOOTH) {
BTSetActive(&but[BRAW], 1);
BTSetActive(&but[BDITH], 0);
BTSetActive(&but[BSMOOTH],1); /* color editing may require a re-smooth */
}
}
/************************************************************************/
int xvErrorHandler(disp, err)
Display *disp;
XErrorEvent *err;
{
char buf[128];
xerrcode = err->error_code;
/* BadAlloc errors (on a XCreatePixmap() call)
and BadAccess errors on XFreeColors are 'ignoreable' errors */
if (xerrcode == BadAlloc ||
(xerrcode == BadAccess && err->request_code==88)) return 0;
else {
/* all other errors are 'fatal' */
XGetErrorText(disp, xerrcode, buf, 128);
fprintf(stderr,"X Error: %s\n",buf);
fprintf(stderr," Major Opcode: %d\n",err->request_code);
exit(-1);
}
return 0;
}